package com.zhanghu.backendZray.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zhanghu.backendZray.cache.ContextCache;
import com.zhanghu.backendZray.converter.AlbumCollectionConverter;
import com.zhanghu.backendZray.enums.PendingTaskTypeEnum;
import com.zhanghu.backendZray.manager.role.UserRoleMenuManager;
import com.zhanghu.backendZray.mapper.AlbumCollectionMapper;
import com.zhanghu.backendZray.pojo.dto.UserTokenInfo;
import com.zhanghu.backendZray.pojo.entity.AlbumCollection;
import com.zhanghu.backendZray.pojo.entity.FamilyGroup;
import com.zhanghu.backendZray.pojo.entity.PendingTask;
import com.zhanghu.backendZray.pojo.entity.User;
import com.zhanghu.backendZray.pojo.request.album.AlbumCollectionPageRequest;
import com.zhanghu.backendZray.pojo.request.album.AlbumCollectionRequest;
import com.zhanghu.backendZray.pojo.request.album.InviteFamilyGroupRequest;
import com.zhanghu.backendZray.pojo.request.album.InviteFamilyResultRequest;
import com.zhanghu.backendZray.pojo.request.user.UserPageRequest;
import com.zhanghu.backendZray.pojo.vo.FileVo;
import com.zhanghu.backendZray.pojo.vo.UserVo;
import com.zhanghu.backendZray.pojo.vo.albumCollection.AlbumCollectionVo;
import com.zhanghu.backendZray.pojo.vo.albumCollection.IntervalPendingTaskVo;
import com.zhanghu.backendZray.pojo.vo.albumCollection.PendingTaskVo;
import com.zhanghu.backendZray.service.*;
import com.zhanghu.backendZray.websocket.WebsocketServer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 相册合集表 服务实现类
 * </p>
 *
 * @author zhangdong
 * @since 2024-08-17
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AlbumCollectionServiceImpl extends ServiceImpl<AlbumCollectionMapper, AlbumCollection> implements AlbumCollectionService {
    private final AlbumCollectionConverter albumCollectionConverter;
    private final FileService fileService;
    private final UserService userService;
    private final PendingTaskService pendingTaskService;
    private final FamilyGroupService familyGroupService;
    private final UserRoleMenuManager userRoleMenuManager;
    private final UserOnlineTokenService userOnlineTokenService;

    /**
     * 新增
     *
     * @param request
     */
    @Override
    public void add(AlbumCollectionRequest request) {
        request.setId(null);
        request.setUserId(ContextCache.currentUserId());
        AlbumCollection albumCollection = albumCollectionConverter.input2Entity(request);
        albumCollection.setFileIdList("[]");
        baseMapper.insert(albumCollection);
    }

    /**
     * 修改
     *
     * @param request
     */
    @Override
    public void update(AlbumCollectionRequest request) {
        LambdaUpdateWrapper<AlbumCollection> updateWrapper = new LambdaUpdateWrapper<AlbumCollection>()
                .eq(AlbumCollection::getId, request.getId())
                .set(AlbumCollection::getCollectionName, request.getCollectionName());
        update(updateWrapper);
    }

    /**
     * 分页查询
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Page<AlbumCollectionVo> page(AlbumCollectionPageRequest request) {
        Page<AlbumCollection> pageQuery = new Page<>(request.getPageNum(), request.getPageSize());
        LambdaQueryWrapper<AlbumCollection> queryWrapper = new LambdaQueryWrapper<AlbumCollection>()
                .in(CollUtil.isNotEmpty(request.getIdList()), AlbumCollection::getId, request.getIdList())
                .eq(AlbumCollection::getUserId, ContextCache.currentUserId())
                .like(StrUtil.isNotEmpty(request.getCollectionName()), AlbumCollection::getCollectionName, request.getCollectionName())
                .orderByDesc(AlbumCollection::getId);
        if (request.getStartDate() != null) {
            queryWrapper.between(AlbumCollection::getCreateTime,
                    LocalDateTime.of(request.getStartDate(), LocalTime.of(0, 0, 0)),
                    LocalDateTime.of(request.getEndDate(), LocalTime.of(23, 59, 59)));
        }
        Page<AlbumCollection> page = baseMapper.selectPage(pageQuery, queryWrapper);
        List<AlbumCollection> list = page.getRecords();
        List<AlbumCollectionVo> userVos = getAlbumCollectionVos(list);
        Page<AlbumCollectionVo> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        resultPage.setRecords(userVos);
        return resultPage;
    }

    private List<AlbumCollectionVo> getAlbumCollectionVos(List<AlbumCollection> list) {
        List<AlbumCollectionVo> userVos = albumCollectionConverter.entity2Vos(list);
        if (CollUtil.isNotEmpty(userVos)) {
            List<Integer> converFileIdList = userVos.stream().map(r -> r.getCoverFileId()).distinct().collect(Collectors.toList());
            List<Integer> fileIdListResult = Lists.newArrayList();
            for (AlbumCollectionVo userVo : userVos) {
                fileIdListResult.addAll(userVo.getFileIdList());
            }
            fileIdListResult.addAll(converFileIdList);
            fileIdListResult = fileIdListResult.stream().distinct().collect(Collectors.toList());
            List<FileVo> fileVos = fileService.listByIds(fileIdListResult);
            Map<Integer, FileVo> fileMap = fileVos.stream().collect(Collectors.toMap(FileVo::getId, Function.identity()));
            for (AlbumCollectionVo userVo : userVos) {
                Integer coverFileId = userVo.getCoverFileId();
                FileVo fileVo = fileMap.get(coverFileId);
                if (fileVo != null) {
                    userVo.setCoverFilePreviewUrl(fileVo.getPreviewUrl());
                }
                List<Integer> fileIdList = userVo.getFileIdList();
                if (CollUtil.isNotEmpty(fileIdList)) {
                    List<String> fileDetailVoList = fileIdList.stream().map(r -> {
                        FileVo tempFileVo = fileMap.get(r);
                        if (tempFileVo != null) {
                            return tempFileVo.getUrl().get(0);
                        }
                        return null;
                    }).collect(Collectors.toList());
                    userVo.setFileUrlList(fileDetailVoList);
                }
            }
        }
        return userVos;
    }

    @Override
    public List<AlbumCollectionVo> listAll() {
        FamilyGroup familyGroup = familyGroupService.getOne(new LambdaQueryWrapper<FamilyGroup>().eq(FamilyGroup::getUserId, ContextCache.currentUserId()));
        Integer sponsor = Optional.ofNullable(familyGroup).map(FamilyGroup::getSponsor).orElse(null);
        List<Integer> userIdList = Lists.newArrayList(ContextCache.currentUserId());
        if (sponsor != null) {
            List<Integer> tempUserIdList = familyGroupService.list(new LambdaQueryWrapper<FamilyGroup>()
                            .eq(FamilyGroup::getSponsor, sponsor)
                            .notIn(FamilyGroup::getUserId, ContextCache.currentUserId()))
                    .stream().map(FamilyGroup::getUserId).collect(Collectors.toList());
            userIdList.addAll(tempUserIdList);
        }
        LambdaQueryWrapper<AlbumCollection> queryWrapper = new LambdaQueryWrapper<AlbumCollection>()
                .in(AlbumCollection::getUserId, userIdList)
                .orderByDesc(AlbumCollection::getId);
        List<AlbumCollection> list = list(queryWrapper);
        return getAlbumCollectionVos(list);
    }

    /**
     * 邀请家庭成员
     *
     * @param inviteFamilyGroupRequest
     */
    @Override
    public void inviteFamilyGroup(InviteFamilyGroupRequest inviteFamilyGroupRequest) {
        // 新增待办事项 等待对方同意
        User user = userService.getByWxNickName(inviteFamilyGroupRequest.getWxNickName());
        Assert.notNull(user, "此用户不存在，请确保对方已登录过此网站！");
        UserTokenInfo userTokenInfo = ContextCache.currentUser();
        PendingTask pendingTask = new PendingTask();
        pendingTask.setUserId(user.getId());
        pendingTask.setSponsor(userTokenInfo.getId());
        pendingTask.setType(PendingTaskTypeEnum.INVITE_FAMILY_GROUP.getType());
        pendingTask.setTitle(PendingTaskTypeEnum.INVITE_FAMILY_GROUP.getDes());
        String content = String.format("%s邀请你加入家庭成员组，加入后，可以共享家庭相册！", userTokenInfo.getWxNickName());
        pendingTask.setContent(content);
        pendingTaskService.save(pendingTask);
        IntervalPendingTaskVo pendingTaskVo = pendingTaskVoWrapper(pendingTask);
        boolean sendSuccess = WebsocketServer.sendMessage(user.getId(), JSON.toJSONString(pendingTaskVo));
        if (sendSuccess) {
            pendingTask.setSendStatus(sendSuccess ? (byte) 1 : (byte) 0);
            pendingTaskService.updateById(pendingTask);
        }
    }

    /**
     * 分页查询所有家庭成员
     *
     * @param request
     * @return
     */
    @Override
    public Page<UserVo> familyGroupPage(UserPageRequest request) {
        LambdaQueryWrapper<FamilyGroup> familyGroupLambdaQueryWrapper = new LambdaQueryWrapper<FamilyGroup>()
                .eq(FamilyGroup::getUserId, ContextCache.currentUserId());
        FamilyGroup one = familyGroupService.getOne(familyGroupLambdaQueryWrapper);
        if (one == null) {
            return new Page<>(request.getPageNum(), request.getPageSize());
        }
        Integer sponsor = one.getSponsor();
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>()
                .like(StrUtil.isNotEmpty(request.getName()), User::getName, request.getName())
                .like(StrUtil.isNotEmpty(request.getPhone()), User::getPhone, request.getPhone());
        List<User> userList = userService.list(userLambdaQueryWrapper);
        List<Integer> userIdList = userList.stream().map(User::getId).distinct().collect(Collectors.toList());
        Page<FamilyGroup> pageQuery = new Page<>(request.getPageNum(), request.getPageSize());
        LambdaQueryWrapper<FamilyGroup> familyGroupPageWrapper = new LambdaQueryWrapper<FamilyGroup>()
                .eq(FamilyGroup::getSponsor, sponsor)
                .in(CollUtil.isNotEmpty(userIdList), FamilyGroup::getUserId, userIdList);
        Page<FamilyGroup> page = familyGroupService.getBaseMapper().selectPage(pageQuery, familyGroupPageWrapper);
        List<FamilyGroup> records = page.getRecords();
        List<Integer> userIdResList = records.stream().map(r -> r.getUserId()).distinct().collect(Collectors.toList());
        Map<Integer, User> userMap = userService.listByIds(userIdResList).stream()
                .collect(Collectors.toMap(r -> r.getId(), Function.identity()));
        List<UserVo> resultList = records.stream().map(r -> {
            Integer userId = r.getUserId();
            UserVo vo = new UserVo();
            vo.setId(userId);
            User user = userMap.get(userId);
            if (user == null) {
                return null;
            }
            vo.setName(user.getName());
            vo.setPhone(user.getPhone());
            vo.setWxNickName(user.getWxNickName());
            vo.setWxAvatar(user.getWxAvatar());
            return vo;
        }).collect(Collectors.toList());
        Page<UserVo> resultPage = new Page<>(request.getPageNum(), request.getPageSize(), page.getTotal());
        resultPage.setRecords(resultList);
        return resultPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitInviteResult(InviteFamilyResultRequest inviteFamilyResultRequest) {
        Integer id = inviteFamilyResultRequest.getId();
        Boolean agree = inviteFamilyResultRequest.getAgree();
        PendingTask pendingTask = pendingTaskService.getById(id);
        Assert.notNull(pendingTask, "不存在此待办事项！");
        Byte status = pendingTask.getStatus();
        Assert.isTrue(status == (byte) 0, "当前状态，不支持此操作！");
        pendingTask.setStatus(agree ? (byte) 1 : (byte) 2);
        pendingTaskService.updateById(pendingTask);
        pendingTaskMesPush(pendingTask.getUserId());
        if (!agree) return;
        // 同意邀请后，加入家庭成员组
        Integer userId = pendingTask.getUserId();
        Integer sponsor = pendingTask.getSponsor();
        List<FamilyGroup> familyGroupList = familyGroupService.list(new LambdaQueryWrapper<FamilyGroup>().
                in(FamilyGroup::getUserId, Arrays.asList(userId, sponsor)));
        Integer oldSponsor = null;
        if (!CollUtil.isEmpty(familyGroupList)) {
            // 当存在两条数据，说明是彼此邀请，直接pass
            if (familyGroupList.size() == 2) {
                return;
            }
            // 当只存在一条数据，说明是发起人邀请的别人
            FamilyGroup familyGroup = familyGroupList.get(0);
            oldSponsor = familyGroup.getSponsor();
        }
        boolean sponsorNeedInsert = CollUtil.isEmpty(familyGroupList);
        if (oldSponsor == null) {
            oldSponsor = sponsor;
        }
        List<FamilyGroup> needInsertList = new ArrayList<>(2);
        FamilyGroup familyGroup = new FamilyGroup();
        familyGroup.setUserId(userId);
        familyGroup.setSponsor(oldSponsor);
        needInsertList.add(familyGroup);
        if (sponsorNeedInsert) {
            FamilyGroup sponsorFamily = new FamilyGroup();
            sponsorFamily.setUserId(oldSponsor);
            sponsorFamily.setSponsor(oldSponsor);
            needInsertList.add(sponsorFamily);
        }
        familyGroupService.saveBatch(needInsertList);
        // 为被邀请人新增家庭组角色
        userRoleMenuManager.addFamilyRole(userId);
    }

    /**
     * 获取指定人员的待办事项并推送
     */
    @Override
    public IntervalPendingTaskVo pendingTaskMesPush(Integer userId) {
        List<PendingTask> list = pendingTaskService.list(new LambdaQueryWrapper<PendingTask>()
                .eq(PendingTask::getUserId, userId)
                .and(q -> q.eq(PendingTask::getSendStatus, (byte) 0).or().eq(PendingTask::getStatus, (byte) 0)));
        List<PendingTask> showList = list.stream().filter(r -> r.getSendStatus().equals((byte) 0)).collect(Collectors.toList());
        List<PendingTask> pendingTaskList = list.stream().filter(r -> r.getStatus().equals((byte) 0)).collect(Collectors.toList());
        IntervalPendingTaskVo taskVo = new IntervalPendingTaskVo(convertVo(showList), convertVo(pendingTaskList));
        boolean sendSuccess = WebsocketServer.sendMessage(userId, JSON.toJSONString(taskVo));
        if (sendSuccess) {
            showList.forEach(r -> r.setSendStatus((byte) 1));
            pendingTaskService.updateBatchById(showList);
        }
//        userOnlineTokenService.updateUserStatusAndTokenRenewal(ContextCache.currentUserId());
        return taskVo;
    }

    /**
     * 单个待办事项组装
     */
    @Override
    public IntervalPendingTaskVo pendingTaskVoWrapper(PendingTask task) {
        List<PendingTask> pendingTasks = Lists.newArrayList(task);
        return new IntervalPendingTaskVo(convertVo(pendingTasks), convertVo(pendingTasks));
    }

    private List<PendingTaskVo> convertVo(List<PendingTask> list) {
        return list.stream().map(r -> {
            PendingTaskVo vo = new PendingTaskVo();
            BeanUtil.copyProperties(r, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<PendingTaskVo> listAllPendingTaskTodo() {
        List<PendingTask> list = pendingTaskService.list(new LambdaQueryWrapper<PendingTask>()
                .eq(PendingTask::getUserId, ContextCache.currentUserId())
                .eq(PendingTask::getStatus, (byte) 0));
        List<PendingTaskVo> resultList = list.stream().map(r -> {
            PendingTaskVo vo = new PendingTaskVo();
            BeanUtil.copyProperties(r, vo);
            return vo;
        }).collect(Collectors.toList());
        return resultList;
    }

    @Override
    public void delete(int id) {
        baseMapper.deleteById(id);
    }

    /**
     * 获取合集中的所有文件id集合
     */
    @Override
    public List<Integer> listAllFileId(int id) {
        return Optional.ofNullable(getById(id))
                .map(r -> JSON.parseArray(r.getFileIdList(), Integer.class))
                .orElse(Collections.emptyList());
    }

    /**
     * 获取合集中的封面文件id
     */
    @Override
    public Integer getPreviewFileId(int id) {
        return Optional.ofNullable(getById(id))
                .map(r -> r.getCoverFileId() == 0 ? null : r.getCoverFileId())
                .orElse(null);
    }

    /**
     * 配置封面
     */
    @Override
    public void coverFileSetting(AlbumCollectionRequest request) {
        LambdaUpdateWrapper<AlbumCollection> updateWrapper = new LambdaUpdateWrapper<AlbumCollection>()
                .eq(AlbumCollection::getId, request.getId())
                .set(AlbumCollection::getCoverFileId, request.getCoverFileId());
        update(updateWrapper);
    }

    /**
     * 配置合集照片
     */
    @Override
    public void fileSetting(AlbumCollectionRequest request) {
        Assert.isTrue(CollUtil.isNotEmpty(request.getFileIdList()), "合集照片不能为空");
        AlbumCollection albumCollection = getById(request.getId());
        Assert.isTrue(albumCollection != null, "此合集不存在，请刷新页面！");
        Integer coverFileId = albumCollection.getCoverFileId();
        LambdaUpdateWrapper<AlbumCollection> updateWrapper = new LambdaUpdateWrapper<AlbumCollection>()
                .eq(AlbumCollection::getId, request.getId())
                .set(AlbumCollection::getFileIdList, JSON.toJSONString(request.getFileIdList()))
                .set(coverFileId == null || coverFileId == 0,
                        AlbumCollection::getCoverFileId, request.getFileIdList().get(0));
        update(updateWrapper);
    }

}
